﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Lon.Util;

namespace Lon.Dev
{
    class CommDevice
    {
        private Socket s;
        private int devId;
        private int portNo;

        private String ip;

        public int DevId
        {
            get { return devId; }
            set
            {
                devId = value;
                foreach (var frameProcesser in processerDict.Values)
                {
                    frameProcesser.DevAddr = value;
                }
            }
        }

        public int PortNo
        {
            get { return portNo; }
            set
            {
                portNo = value;
                foreach (var frameProcesser in processerDict.Values)
                {
                    frameProcesser.PortNo = value;
                }
            }
        }

        public IRawDataShower RawDataShower = null;
        public IMessageShower MessageShower = null;
        private VerProcesser verProcesser;
        private FileUpdateProcesser fileUpdateProcesser;
        Dictionary<int, FrameProcesser> processerDict = new Dictionary<int, FrameProcesser>();
        private DevTypeManager devTypeManager;
        public CommDevice(String ip)
        {

            this.ip = ip;
            verProcesser = new VerProcesser(this);
            fileUpdateProcesser = new FileUpdateProcesser(this);
            processerDict[0x02] = fileUpdateProcesser;
            processerDict[0x07] = verProcesser;
            devTypeManager = DevTypeManager.Read(PathHelper.GetApplicationPath() + "\\DevTypeConfig.xml");
        }


        private void RxPorc()
        {
         
            while (true)
            {
                try
                {    
                    s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    ShowMessage("Info", "开始连接");
                    s.Connect(ip, 8686);
                    SocketReader reader = new SocketReader(s);
                    ShowMessage("Info", "连接成功");
                    while (true)
                    {

                        var frame = ReadFrame(reader);
                        if (frame[0] == 0x01)
                        {
                            continue;
                        }  
                     
                        ShowRawData("接收", frame);
                        Process(frame);
                       
                        
                    }
                }
                catch (Exception ex)
                {
                    Thread.Sleep(10000);
                }

            }

        }


        private void Process(byte[] rawData)
        {
            if (rawData[0] == 0xf3)
            {
                int portNo = rawData[1];
                int statu = rawData[10];
                ShowMessage("Info", String.Format("端口{0}状态{1}", portNo, statu == 1 ? "调试状态" : "工作状态"));
            }
            else if(rawData[0]==0xfe)
            {
                var str = String.Format("{0}.{1}.{2}.{3},Hash:{4}",
                    rawData[10],rawData[11],rawData[12],rawData[13],
                    Encoding.ASCII.GetString(rawData,14,40)
                    );
                ShowMessage("Info",str);

            }
            if (rawData[0] == 0x02)
            {
                NetFrame frame = new NetFrame();
                frame.Parse(rawData);
                if (processerDict.ContainsKey(frame.DataType))
                {
                    processerDict[frame.DataType].Process(frame);
                }

            }
        }

        private DateTime ReadDateTime(BinaryReader br)
        {

            double updateSenconds = br.ReadInt32();
            updateSenconds += br.ReadInt32() * 0.000001;


            DateTime now = DateTime.Now;

            return now;

            //long sec = br.ReadInt32();
            //long miscSec = br.ReadInt32();

            //long ticks = sec * 1000 + miscSec / 1000; //毫秒为单位

            //TicksTime = TicksTime.AddMilliseconds(ticks - lastTicks);
            //if (Math.Abs((TicksTime - DateTime.Now).TotalSeconds) > 5)
            //{
            //    TicksTime = DateTime.Now;
            //}


            //lastTicks = ticks;



            //return TicksTime;
        }

        private byte ReadPortType(BinaryReader br)
        {
            return br.ReadByte();
        }
        private byte ReadPortNum(BinaryReader br)
        {
            return br.ReadByte();
        }
        private int ReadSensorType(BinaryReader br)
        {
            return br.ReadByte();
        }



        private int ReadDataLength(BinaryReader br)
        {
            return br.ReadUInt16();
        }

        private byte ReadSrcAddr(BinaryReader br)
        {
            return br.ReadByte();
        }

        private byte ReadDstAddr(BinaryReader br)
        {
            return br.ReadByte();
        }
        private byte ReadDataType(BinaryReader br)
        {
            return br.ReadByte();
        }

        private byte[] ReadFrame(SocketReader reader)
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);
            ReadStart(reader);
            while (true)
            {
                byte val = reader.ReadByte();
                if (val == 0x10)
                {
                    byte nextByte = reader.ReadByte();
                    if (nextByte == 0x10)
                    {
                        bw.Write((byte)0x10);
                    }
                    else if (nextByte == 0x03)
                    {
                        return ms.ToArray();
                    }
                    else
                    {
                        Console.WriteLine("0x10后收到非法字符");
                    }
                }
                else
                {
                    bw.Write(val);
                }
            }


        }

        public void SetDebugMode(byte portNo, bool enter)
        {
            byte[] data = new byte[1];
            data[0] = enter ? (byte)0x01 : (byte)0x02;
            WriteFrame(0xf2, portNo, 0x00, 0xff, data);

        }

        public void QueryDebugMode(byte portNo)
        {
            byte[] data = new byte[1];
            data[0] = 0x00;
            WriteFrame(0xf3, portNo, 0x00, 0xff, data);
        }

        public void WriteFrame(byte cmdType, byte portNo, byte srcAddr, byte dstAddr, byte[] data)
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);

            bw.Write(cmdType);
            bw.Write(portNo);
            bw.Write(srcAddr);
            bw.Write(dstAddr);
            bw.Write(data);
            byte[] frame = ms.ToArray();
            var sendBuf = BuildNetBuf(frame);
            try
            {
                s.Send(sendBuf);
                ShowRawData("发送", frame);
            }
            catch
            {

            }

        }

        private byte[] BuildNetBuf(byte[] txBuf)
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((byte)0x10);
            bw.Write((byte)0x02);
            for (int i = 0; i < txBuf.Length; i++)
            {
                if (txBuf[i] == 0x10)
                {
                    bw.Write((byte)0x10);
                    bw.Write((byte)0x10);
                }
                else
                {
                    bw.Write(txBuf[i]);
                }
            }
            bw.Write((byte)0x10);
            bw.Write((byte)0x03);
            return ms.ToArray();
        }
        public void QueryVer(byte portNo, byte dstAddr)
        {

            byte[] data = new byte[2];

            data[0] = 0x07;
            data[1] = 0x01;
            WriteFrame(0x02, portNo, 0x00, dstAddr, data);
            VerInfo ver;
           


        }
        public void UIQueryVer(byte portNo, byte dstAddr)
        {

            byte[] data = new byte[2];

            data[0] = 0x07;
            data[1] = 0x01;
            WriteFrame(0x02, portNo, 0x00, dstAddr, data);
            VerInfo ver;
            if (verProcesser.ReadVerInfo(out ver, 5 * 1000))
            {
                ShowMessage("Info", String.Format("设备类型{0},当前版本号[{1}.{2}],日期:{3:yy/MM/dd}"
                                                   , ver.DevType, ver.MajorVer, ver.MinorVer, ver.RelaseData));
            }


        }

        private void ReadStart(SocketReader reader)
        {
            byte val = reader.ReadByte();
            while (true)
            {
                while (val != 0x10)
                {
                    val = reader.ReadByte();
                }
                val = reader.ReadByte();
                if (val == 0x02)
                {
                    return;
                }
            }

        }

        private void ShowRawData(string dir, byte[] frame)
        {
            if (RawDataShower != null)
            {
                RawDataShower.ShowRawData(dir, frame);
            }
        }

        private void ShowMessage(string info, string msg)
        {
            if (MessageShower != null)
            {
                MessageShower.ShowMessage(info, msg);
            }

        }

        public void Start()
        {
            Thread thread = new Thread(RxPorc);
            thread.IsBackground = true;
            thread.Start();
        }
        Thread workThread;
        private String updateFile;
        public void Update(string path)
        {
            this.updateFile = path;
            
            workThread=new Thread(WorkProc);
            workThread.IsBackground = true;
            workThread.Start();


        }

        private void WorkProc()
        {
           
            VerInfo ver;
            int readCount = 0;
            while(true)
            {
                readCount++;
                QueryVer((byte)this.PortNo,(byte)this.DevId);
                if (verProcesser.ReadVerInfo(out ver, 5000))
                {
                    ShowMessage("Info",String.Format("设备类型{0},当前版本号[{1}.{2}],日期:{3:yy/MM/dd}"
                                                    ,ver.DevType,ver.MajorVer,ver.MinorVer,ver.RelaseData));
                    break;
                }
                if (readCount > 2)
                {
                    ShowMessage("Warning","读取版本信息失败");
                    return;
                }
            }


            var devTypeInfo= devTypeManager.TypeList.Find((DevTypeInfo typeInfo)
                =>
            {
                if (typeInfo.Id == ver.DevType)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            });
            if (devTypeInfo == null)
            {
                ShowMessage("Warning",String.Format("为找到对应的传感器类型{0}",ver.DevType));
                return;
            }

            SendRst((byte)PortNo,(byte)this.DevId);
            Thread.Sleep(3000);

            using (FileStream fs = new FileStream(updateFile, FileMode.Open))
            {
                int len = (int)fs.Length;
                int frameLen = devTypeInfo.FirmwareUpdateSpan;
                int frameCount = (int)Math.Ceiling(len*1.0/frameLen);
                for (int i = 0; i < frameCount; i++)
                {
                    ShowMessage("Info", String.Format("正在发送{0}/{1}帧", i+1,frameCount));  
                    int frameId = i;
                    int sendBytesCount = frameLen;
                    if (frameId == frameCount - 1)
                    {
                        frameId |= 0x8000;
                        sendBytesCount =(int)( fs.Length - fs.Position);
                    }
                    byte[] sendBytes=new byte[sendBytesCount+8];
                    MemoryStream ms=new MemoryStream(sendBytes);
                    BinaryWriter bw=new BinaryWriter(ms);
                    bw.Write((byte)0x02);
                    bw.Write((UInt16)frameId);
                    if (devTypeInfo.FirmwareId <= 0)
                    {
                        bw.Write((byte) (ver.DevType + 1));
                    }
                    else
                    {
                        bw.Write((byte)devTypeInfo.FirmwareId);
                    }
                    bw.Write((byte)0x01);
                    bw.Write((byte)0x00);
                    for (int bytesCount = 0; bytesCount < sendBytesCount; bytesCount++)
                    {
                        bw.Write((byte)fs.ReadByte());
                    }

                    var crc=CheckHelper.CalcCRC(sendBytes, 1, sendBytes.Length - 3);
                    sendBytes[sendBytes.Length-2] = (byte)(crc & 0xff);
                    sendBytes[sendBytes.Length - 1] = (byte)((crc >> 8) & 0xff);
                    WriteFrame(0x02,(byte)PortNo,0x01,(byte)this.DevId,sendBytes);
                    int outFrameIndex, outResult;
                    if (fileUpdateProcesser.ReadResult(out outFrameIndex, out outResult, 20*1000))
                    {
                        if (outResult != 0)
                        {
                            ShowMessage("Warnning", String.Format("返回类型码错误{0}",outResult));
                            return;
                        }
                    }
                    else
                    {
                        ShowMessage("Warnning","读应答超时");
                        return;
                    }

                }
            }
            ShowMessage("Info", "升级完成");  

        }

        private void SendRst(byte port,byte dstAddr)
        {
            byte[] data = new byte[1];

          

            data[0] = 0x0f;
            
            WriteFrame(0x02, port, 0x01, dstAddr, data);
        }

        internal void QueryVer()
        {
            byte[] data = new byte[0];

          
            WriteFrame(0xFE, 0x00, 0x00, 0x00, data);
        }

        internal void Test(string path)
        {
            using (FileStream fs = new FileStream(path, FileMode.Open))
            {
                int len = (int)fs.Length;
                int frameLen = 500;    //devTypeInfo.FirmwareUpdateSpan
                int frameCount = (int)Math.Ceiling(len * 1.0 / frameLen);
                for (int i = 0; i < frameCount; i++)
                {
                    ShowMessage("Info", String.Format("正在发送{0}/{1}帧", i, frameCount));
                    int frameId = i;
                    int sendBytesCount = frameLen;
                    if (frameId == frameCount - 1)
                    {
                        frameId &= 0x8000;
                        sendBytesCount = (int)(fs.Length - fs.Position);
                    }
                    byte[] sendBytes = new byte[sendBytesCount + 7];
                    MemoryStream ms = new MemoryStream(sendBytes);
                    BinaryWriter bw = new BinaryWriter(ms);
                    bw.Write((byte)0x02);
                    bw.Write((UInt16)frameId);
                    bw.Write((byte)(0x16 | 0x80));
                    bw.Write((byte)0x01);
                    bw.Write((byte)0x01);
                    for (int bytesCount = 0; bytesCount < sendBytesCount; bytesCount++)
                    {
                        bw.Write((byte)fs.ReadByte());
                    }

                    var crc = CheckHelper.CalcCRC(sendBytes, 1, sendBytes.Length - 3);
                    sendBytes[sendBytes.Length - 2] = (byte)(crc & 0xff);
                    sendBytes[sendBytes.Length - 2] = (byte)((crc >> 8) & 0xff);
                    WriteFrame(0x02, (byte)PortNo, 0x00, (byte)this.DevId, sendBytes);
                    int outFrameIndex, outResult;
                    if (fileUpdateProcesser.ReadResult(out outFrameIndex, out outResult, 10 * 1000))
                    {
                        if (outResult != 0)
                        {
                            ShowMessage("Warnning", String.Format("返回类型码错误{0}", outResult));
                            return;
                        }
                    }
                    else
                    {
                        ShowMessage("Warnning", "读应答超时");
                        return;
                    }

                }
            }
        }

        public void WriteCanFrame(byte portNo,int canId, byte[] data)
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);
         
          
            bw.Write((byte)0x01);
            bw.Write((byte)portNo);
            bw.Write(canId);
            bw.Write((byte)data.Length);
            bw.Write(data);
            var sendBuf = BuildNetBuf(ms.ToArray());
            try
            {
                s.Send(sendBuf);
               // ShowRawData("发送", frame);
            }
            catch
            {

            }
         
        }
    }
}
